Jeśli moja strona Ci pomogła, i chcesz aby była bardziej rozwijana, wesprzyj mnie
buy me a coffee
|
Bean możemy identyfikować n 3 sposoby:
I. Typ
II. Typ i kwalifikator
III. przez nazwę (adnotacja @Named)
I) przez Typ
1. Teraz pokażę przykłady dla konfiguracji beans.xml bean-discovery-mode="all".
Czyli każda klasa jest zarządzana.
Zobaczmy pierwszy przykład:
implementujemy interface:
public interface MyInterface {
String getIdName();
}
następnie używamy jego implementacji w klasie:
public class MyBean implements MyInterface {
public String getIdName() {
return "MyBean";
}
}
i już taką implementację możemy wstrzykiwać używając adnotacji @Inject:
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
@ApplicationScoped
public class MyController {
@Inject
private MyBean myBean;
@Inject
private MyInterface myInterface;
public String getNameMyInterface() {
return myInterface.getIdName(); // wyświetli: "MyBean"
}
public String getNameMyBean() {
return myBean.getIdName(); // wyświetli: "MyBean"
}
}
Ale gdy np implementujemy drugi raz interface lub dziedziczymy drugi raz
po tej samej klasie będzie błąd, niejednoznaczności wstrzyknięcia.
dodajemy do powyższych klas klasę OtherBean.java:
public class OtherBean extends MyBean {
public String getIdName() {
return "OtherBean";
}
}
To nam spowoduje błąd deployowania aplikacji, przez co nasza aplikacja nie będzie uruchomiona
Jeden ze sposobów na rozwiązanie tego problemu to ustawienie @Veted na klasie którą nie chcemy mieć zarządzanej przez CDI.
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.inject.Vetoed;
@Vetoed
public class MyBean implements MyInterface {
@Override
public String getIdName() {
return "MyBean";
}
}
public class MyController {
@Inject
private MyInterface myInterface;
@Inject
private MyBean myBean;
public String getNameMyInterface() {
return myInterface.getIdName(); // wypisze: "OtherBean"
}
public String getNameMyBean() {
return myBean.getIdName(); // wypisze: "OtherBean"
}
}
2.Drugi przykład to implementacja jednego inteface-u przez dwie klasy:
public interface MyInterface {
String getIdName();
}
public class MyBean implements MyInterface {
public String getIdName() {
return "MyBean";
}
}
public class OtherBean implements MyInterface {
public String getIdName() {
return "OtherBean";
}
}
I znowu mamy błąd z brakiem jednoznaczności wstrzyknięcia.
Możemy użyć adnotacji @Any na polu Instance<T> przy wstrzyknięciu zależności.
Instance jest to interface który powoduje leniwe wstrzyknięcie beanu
Bean pobieramy używając metody get(). Uzyskujemy w ten sposób dynamicznie aktualną instancję beana.
Instance implementuje on interface iterable<T> przez co możemy użyć pętli forEach.
@Named
@ApplicationScoped
public class MyFirstController {
@Inject
@Any
private Instance<MyInterface> myInterface;
public String getNameFromInterface() {
StringBuilder sb = new StringBuilder();
for (MyInterface mI : myInterface) {
sb.append(mI.getIdName());
sb.append(":");
}
return sb.toString();
}
}
Tyle przechodzimy po wszystkich elementach które są Beanem dla danego interface-u.
3. Zobaczmy trzeci sposób na rozwiązanie tego problemu
Aby ten błąd rozwiązać możemy użyć adnotacji @Alternative, wtedy ta klasa będzie
użyta jako alternatywna. @Default będzie w pierwszej kolejności wstrzyknięta.
@Default jest domyślną wartością, nie trzeba jej dodawać, dodanie jej jawnie jest nadmiarowe.
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.inject.Alternative;
@Alternative
public class MyBean implements MyInterface {
@Override
public String getIdName() {
return "MyBean";
}
}
@Named
@ApplicationScoped
public class MyController {
@Inject
private MyInterface myInterface;
public String getNameFromInterface() {
return myInterface.getIdName(); // wypisane zostanie: "OtherBean"
}
}
Ale przypatrzmy się jeszcze interface-owi Instance<>.
Pobiera on aktualną instancję klasy, najbardziej zaktualizowaną.
Mamy klasę:
package pl.edu.java.cdi.managedBeans;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class OtherBean implements MyInterface {
private String strDate;
public OtherBean() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss.SSS");
strDate = dateFormat.format(new Date());
}
@Override
public String getIdName() {
return strDate;
}
}
Wstrzykujemy ją do kontrolera:
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
@ApplicationScoped
public class MyFirstController {
@Inject
private MyInterface myInterface;
@Inject
private Instance<MyInterface> myInterfaceInstance;
public String getNameFromInterface() {
StringBuilder sb = new StringBuilder();
for (int x=0;x<5;x++) {
try {
Thread.sleep(1000);
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
sb.append(myInterface.getIdName()); // wyświetlone 5x to samo
sb.append("<br/>");
}
return sb.toString();
}
public String getNameFromInterfaceInstance() {
StringBuilder sb = new StringBuilder();
for (int x=0;x<5;x++) {
try {
Thread.sleep(1000);
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
sb.append(myInterfaceInstance.get().getIdName());
// wyświetlone każdorazowe nowe wartości
sb.append("<br/>");
}
return sb.toString();
}
}
i widzimy że pole "myInterface" jest wstrzyknięte tylko przy ładowaniu klasy Kontrolera.
I wyświetlone jest 5x to samo:
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
2020-19-03 01:19:44.896
Drugie pole myInterfaceInstance wraz z wywołaniem ".get()", tworzy nową instancje przy
każdym wywołaniu metody ".get()". Instancja jest nowa za każdym razem ponieważ domyślny
zasięg klasy (scope), jest @Dependent.
My Interface Instance:
2020-19-03 01:19:50.902
2020-19-03 01:19:51.903
2020-19-03 01:19:52.903
2020-19-03 01:19:53.904
2020-19-03 01:19:54.904
II) przez Typ i kwalifikator
Wstrzyknięcie może być określone przez kwalifikator (Qualifier).
package pl.edu.java.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface QMainBean {}
Dostępne wartości dla adnotacji Retention dla Java 11 pod linkem:
docs.oracle.com/../RetentionPolicy.html
Możliwe wartości dla adnotacji target dla Java 11 pod linkem:
docs.oracle.com/../ElementType.html
public interface MyInterface {
String getIdName();
}
public class MyBean implements MyInterface {
public String getIdName() {
return "MyBean";
}
}
@QMainBean
public class OtherBean implements MyInterface {
public String getIdName() {
return "OtherBean";
}
}
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@ApplicationScoped
public class MyFirstController {
@Inject
@QMainBean
private MyInterface myInterface;
public String getNameFromInterface() {
return myInterface.getIdName(); // wypisne: "OtherBean"
}
}
III) przez nazwę (adnotacja @Named)
public interface MyInterface {
String getIdName();
}
public class MyBean implements MyInterface {
public String getIdName() {
return "MyBean";
}
}
@Named("otherBean")
public class OtherBean implements MyInterface {
public String getIdName() {
return "OtherBean";
}
}
package pl.edu.java.cdi.managedBeans;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@ApplicationScoped
public class MyFirstController {
@Inject
@Named("otherBean")
private MyInterface mysInterface;
public String getNameFromInterface() {
return myInterface.getIdName(); // wypisne: "OtherBean"
}
}
Adnotacja @Named ma specjalną funkcję. W komponentach JSF używane są tylko Kwalifikatory @Named,
tak identyfikujemy beany dla komponentów JSF. i tym sposobem aby połączyć się do klasy kontrolera:
MyFirstController, używamy wyrażenia EL, i możemy dostać się do niego za pomocą:
<h:outputText value="#{myFirstController.getNameFromInterface()}" />
|